package cgUtils

import (
	"crypto/md5"
	"crypto/sha256"
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"

	gonanoid "github.com/matoous/go-nanoid/v2"
)

const (
	NANOID_CUSTOM_WORDS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
)

// 生成22位nanoid
func GenNanoid() string {
	nanoid, err := gonanoid.New()
	if err != nil {
		nanoid = GenTimeString(22)
	}
	return nanoid
}

// 返回由时间组成得字符串
// 可以在其他随机字符串失败时使用，暂时顶替。
func GenTimeString(size int) string {
	ts := time.Now().Format("20060102150405.000")
	ts = strings.ReplaceAll(ts, ".", "")

	tsLen := len(ts)
	if size > tsLen {
		ts = fmt.Sprintf(fmt.Sprintf("%%0%ds", size), ts)
	} else if size < tsLen {
		ts = ts[tsLen-size : tsLen]
	}
	return ts
}

// 生成指定长度随机字符，由NANOID_CUSTOM_WORDS组成
func GenRandomWords(size int) string {
	nanoid, err := gonanoid.Generate(NANOID_CUSTOM_WORDS, size)
	if err != nil {
		nanoid = GenTimeString(size)
	}
	return nanoid
}

func StringMd5(str string) string {
	re := md5.Sum([]byte(str))
	return fmt.Sprintf("%x", re)
}

func Sha256(str string) string {
	rs := sha256.Sum256([]byte(str))
	return fmt.Sprintf("%x", rs)
}

func Len(str string) int {
	return len([]rune(str))
}

func Substring(source string, start int, end int) string {
	var r = []rune(source)
	length := len(r)

	if start < 0 || start > end {
		return ""
	}

	if (start == 0 && end == length) || (end > length) {
		return source
	}

	var substring = ""
	for i := start; i < end; i++ {
		substring += string(r[i])
	}

	return substring
}

func StringValue(value interface{}) string {
	var key string
	if value == nil {
		return key
	}

	switch value := value.(type) {
	case float64:
		key = strconv.FormatFloat(value, 'f', -1, 64)
	case float32:
		key = strconv.FormatFloat(float64(value), 'f', -1, 64)
	case int:
		key = strconv.Itoa(value)
	case uint:
		key = strconv.Itoa(int(value))
	case int8:
		key = strconv.Itoa(int(value))
	case uint8:
		key = strconv.Itoa(int(value))
	case int16:
		key = strconv.Itoa(int(value))
	case uint16:
		key = strconv.Itoa(int(value))
	case int32:
		key = strconv.Itoa(int(value))
	case uint32:
		key = strconv.Itoa(int(value))
	case int64:
		key = strconv.FormatInt(value, 10)
	case uint64:
		key = strconv.FormatUint(value, 10)
	case string:
		key = value
	case []byte:
		key = string(value)
	default:
		newValue, _ := json.Marshal(value)
		key = string(newValue)
	}

	return key
}
